package com.evaluationSystem.exception;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSONObject;
import com.evaluationSystem.config.R;
import com.evaluationSystem.config.RCode;
import com.evaluationSystem.entity.SysLogErrorEntity;
import com.evaluationSystem.service.SysLogErrorService;
import com.evaluationSystem.util.HttpContextUtils;
import com.evaluationSystem.util.IpUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.Objects;

@RestControllerAdvice
public class ExceptionHandlers {
    @Autowired
    private SysLogErrorService sysLogErrorService;

    @ExceptionHandler(MethodArgumentNotValidException.class)//参数校验异常
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        return R.of(RCode.LOGIN_FAIL, false, Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);
    }

    @ExceptionHandler(DuplicateKeyException.class)//重复校验异常
    public Object handleDuplicateKeyException(DuplicateKeyException e){
        return R.of(RCode.OPERATION_DUPLICATED, false, e.getMessage(), null);
    }

    @ExceptionHandler(AuthorizationException.class)//认证异常
    public Object handleAuthorizationException(AuthorizationException e) {
        e.printStackTrace();
        return R.failed(RCode.UNAUTHORIZED, "暂无权限操作", null);
    }

    @ExceptionHandler(EvaluationException.class)
    public Object handleEvaluationException(EvaluationException e) {
        return R.failed(e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Object handleException(Exception e){
        e.printStackTrace();

        saveLog(e);

        return R.failed();
    }

    /**
     * 保存异常日志
     */
    private void saveLog(Exception ex){
        SysLogErrorEntity log = new SysLogErrorEntity();

        //请求相关信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setRequestUri(request.getRequestURI());
        log.setRequestMethod(request.getMethod());
        Map<String, String> params = HttpContextUtils.getParameterMap(request);
        if(MapUtil.isNotEmpty(params)){
            log.setRequestParams(JSONObject.toJSONString(params));
        }

        //异常信息
        log.setErrorInfo(getErrorStackTrace(ex));

        //保存
        sysLogErrorService.save(log);
    }

    /**
     * 获取异常信息
     * @param ex  异常
     * @return    返回异常信息
     */
    public static String getErrorStackTrace(Exception ex){
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw, true);
            ex.printStackTrace(pw);
        }finally {
            try {
                if(pw != null) {
                    pw.close();
                }
            } catch (Exception e) {

            }
            try {
                if(sw != null) {
                    sw.close();
                }
            } catch (IOException e) {

            }
        }

        return sw.toString();
    }
}